#
# libgist utility functions
#

"""This module provides various utility functions used by the libgist
configuration scripts."""

#---------------------------- ADMINISTRIVIA -----------------------------

# This file is part of libgist.
#
# libgist is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# libgist is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with libgist; if not, write to the Free Software Foundation, Inc., 59
# Temple Place, Suite 330, Boston, MA 02111-1307 USA.

# REVISION HISTORY
#
# $HeadURL: http://libgist.googlecode.com/svn/branches/wu_dev/conf/conf/utils.py $
# $Id: utils.py 68 2011-09-26 22:44:25Z libgist@gmail.com $

#------------------------------ IMPORTS --------------------------------

# Python standard library
import os, re, subprocess

#------------------------------ CPU COUNT -------------------------------

# How many CPU's do we have?
def num_cpu():
   """Determine the number of CPU's available on the system.

This function tries to figure out how many CPU's the system has. It
raises an exception if it cannot find this number out.

The code for this function was lifted from:
   http://stackoverflow.com/questions/1006289/how-to-find-out-the-number-of-cpus-in-python
"""

   # Python 2.6+
   try:
      import multiprocessing
      return multiprocessing.cpu_count()
   except (ImportError,NotImplementedError):
      pass

   # POSIX
   try:
      res = int(os.sysconf('SC_NPROCESSORS_ONLN'))
      if res > 0:
         return res
   except (AttributeError,ValueError):
      pass

   # Linux
   try:
      res = open('/proc/cpuinfo').read().count('processor\t:')
      if res > 0:
         return res
   except IOError:
      pass

   # BSD
   try:
      sysctl = subprocess.Popen(['sysctl', '-n', 'hw.ncpu'],
                                stdout = subprocess.PIPE)
      scStdout = sysctl.communicate()[0]
      res = int(scStdout)
      if res > 0:
         return res
   except (OSError, ValueError):
      pass

   # Solaris
   try:
      pseudoDevices = os.listdir('/devices/pseudo/')
      expr = re.compile('^cpuid@[0-9]+$')
      res = 0
      for pd in pseudoDevices:
         if expr.match(pd) != None:
            res += 1
      if res > 0:
         return res
   except OSError:
      pass

   # Other UNIXes (heuristic)
   try:
      try:
         dmesg = open('/var/run/dmesg.boot').read()
      except IOError:
         dmesgProcess = subprocess.Popen(['dmesg'],
                                         stdout = subprocess.PIPE)
         dmesg = dmesgProcess.communicate()[0]
      res = 0
      while '\ncpu' + str(res) + ':' in dmesg:
         res += 1
      if res > 0:
         return res
   except OSError:
      pass

   # jython
   try:
      from java.lang import Runtime
      runtime = Runtime.getRuntime()
      res = runtime.availableProcessors()
      if res > 0:
         return res
   except ImportError:
      pass

   # Windows
   try:
      res = int(os.environ['NUMBER_OF_PROCESSORS'])
      if res > 0:
         return res
   except (KeyError, ValueError):
      pass

   # Can't determine number of CPU's; got to have at least one...
   return 1

#------------------------------------------------------------------------

# So things look consistent in everyone's emacs...
# Local Variables:
# indent-tabs-mode: nil
# End:
